class World{
    width;
    height;
    canvas;
    maxTouchX = 800;
    maxTouchY = 300;
    mapWidth = 16000;
    mapHieght = 16000;
    cameraX = 0;
    cameraY = 0;
    cameraWidth = 0;
    cameraHeight = 0;
    screenIsFull = false;
    runner;
    ongoingTouches =  new  Array(); 
    eles={};
    constructor(){
        console.log("init the word...");
        let that = this;
        let body = document.getElementById( 'body' );
        body.innerHTML = '<div><canvas id= "canvas" > Your browser does not support canvas element. </canvas></div><div><input  type="button" id="full" value="全屏"></div>'
        body.innerHTML = body.innerHTML + 'Log: <pre id= "log"  style= "border: 1px solid #ccc;" ></pre>';
        let l1 = window.screen.width;
        let l2 = window.screen.height;
        if(l1 > l2){
            this.width = l1;
            this.height = l2;
        }else{
            this.width = l2;
            this.height = l1;
        }
        this.cameraWidth = this.width;
        this.cameraHeight = this.height;
        console.log(this.width + " " + this.height);
        this.canvas = document.getElementById('canvas');
        // canvas.setAttribute("width",this.width);
        canvas.setAttribute("height",this.height);
        canvas.setAttribute("width",800);
        // canvas.setAttribute("height",400);
        canvas.setAttribute("style","background:#F0F3")
        canvas.setAttribute("maxTouchX",this.maxTouchX);
        canvas.setAttribute("maxTouchY",this.height);

        let fullButton = document.getElementById('full');
        fullButton.setAttribute("world",this);
        fullButton.onclick=function(){
            if (canvas.webkitRequestFullScreen) {
                canvas.webkitRequestFullScreen();
            } else if (canvas.mozRequestFullScreen) {
                canvas.mozRequestFullScreen();
            } else if (canvas.msRequestFullScreen) {
                canvas.msRequestFullScreen();
            }
            canvas.addEventListener( "touchmove" , that.getMaxTouchRange,  false );
        };
        document.addEventListener("fullscreenchange", function(e) {
            that.closeCheckRange()
        });
        document.addEventListener("mozfullscreenchange", function(e) {
            that.closeCheckRange()
        });
        document.addEventListener("webkitfullscreenchange", function(e) {
            that.closeCheckRange()
        });
        document.addEventListener("msfullscreenchange", function(e) {
            that.closeCheckRange()
        });
        // this.adjustCanvas();

        // setInterval(function(){that.runner.log();},5000);

    }
    

    getMaxTouchRange(evt){
        // alert(1);
        evt.preventDefault();
        var  touches = evt.changedTouches;
        for  ( var  i=0; i < touches.length; i++) {
            let ex=touches[i].pageX;
            let ey=touches[i].pageY;
            if(ex >= this.getAttribute("width")){
                this.setAttribute("width",ex);
                this.setAttribute("maxTouchX",ex);
                this.setAttribute("maxTouchY",ey);
            }
            if(ey >= this.getAttribute("height")){
                this.setAttribute("height",ey);
            }
        }
    }

    closeCheckRange(){
        this.log(this.screenIsFull);
        this.screenIsFull = !this.screenIsFull;
        if(!this.screenIsFull){
            this.log("remove");
            let that = this;
            canvas.removeEventListener( "touchmove" , that.getMaxTouchRange,  false );
        }
        
    }

    log(msg) {
        var  p = document.getElementById( 'log' );
        p.innerHTML = msg +  "\n"  + p.innerHTML;
    }
            
}




class TouchHander{
    world;
    
    constructor(world){
        this.world = world;
        world.eles.bullets= new  Array(); 
        world.eles.permanent = ["button","line","ball"]
        // world.eles.ball={"shape":"circle","r":25,"x":425,"y":195,"color":"#F002"};
        let play = new Player(425,195,0,0,2,"#F939");

        // let gun = new Gun(100,play.x,play.y,1,1);
        let gun = new SubmachineGun();
        play.setGun(gun);
        play.setWorld(world);
        world.eles.ball = play;
        world.eles.bullets.push(new Bullet(100,200,100,100,1));
        // alert(this.world.eles.ball.r);
        world.eles.npcs = new Array();
        // world.eles.npcs.push(new Npc(200,200,100,100,1));
        this.setCanvasListener();
        this.addpcListener();
    }

    setCanvasListener(){
        let that = this;
        let canvas = this.world.canvas;
        canvas.addEventListener( "touchstart" , function(evt){
            // that.world.log("start touch")
            evt.preventDefault();  //阻止事件的默认行为
            let  touches = evt.changedTouches;
            for  ( let  i=0; i < touches.length; i++) {
              that.world.ongoingTouches.push(that.copyTouch(touches[i]));
            //   that.world.log(JSON.stringify(that.world.ongoingTouches));
            //   that.world.log("maxTouchX"+this.getAttribute("maxTouchX"));
              if(touches[i].pageX < this.getAttribute("maxTouchX")/2 && that.world.eles.button == null){
                let button ={"shape":"circle","r":50,"x":touches[i].pageX,"y":touches[i].pageY,"color":"#0002","role":"button"}
                that.world.eles.button = button;
                // that.world.log(JSON.stringify(that.world.eles));
              }
            }
        },  false );
        canvas.addEventListener( "touchmove" , function(evt){
            // that.world.log("move touch");
            evt.preventDefault();
            let  touches = evt.changedTouches;

            for  ( let  i=0; i < touches.length; i++) {
              let  idx = that.ongoingTouchIndexById(touches[i].identifier);
              if (idx >= 0) {
                let ongoingTouches = that.world.ongoingTouches;
                let eles = that.world.eles;
                let bx=ongoingTouches[idx].pageX;
                let by=ongoingTouches[idx].pageY;
                let ex=touches[i].pageX;
                let ey=touches[i].pageY;
                ongoingTouches[idx].nowX=ex;
                ongoingTouches[idx].nowY=ey;

                
                if(bx < this.getAttribute("maxTouchX")/2 && bx == eles.button.x && by == eles.button.y){
                  eles.ball.setV(ex-bx,ey-by);
                  let line = {"role":"button","shape":"line","ex":touches[i].pageX,"ey":touches[i].pageY,"bx":ongoingTouches[idx].pageX,"by":ongoingTouches[idx].pageY,"color":"#f00"}
                  eles.line=line;
                //   that.world.log(JSON.stringify(line))
                }
                
                // ongoingTouches.splice(idx, 1, copyTouch(touches[i]));   // swap in the new touch record
              }  else  {
                alert( "can't figure out which touch to continue" );
              }
            }
        },  false );

        canvas.addEventListener( "touchend" , function(evt){
            evt.preventDefault();
                // log( "touchend/touchleave." );
                var  touches = evt.changedTouches;
 
                for  ( let  i=0; i < touches.length; i++) {
                  let  idx = that.ongoingTouchIndexById(touches[i].identifier);
                  if (idx >= 0) {
                    let ongoingTouches = that.world.ongoingTouches;
                    let eles = that.world.eles;
                    let bx=ongoingTouches[idx].pageX;
                    let by=ongoingTouches[idx].pageY;
                    let ex=touches[i].pageX;
                    let ey=touches[i].pageY;
                    if(eles.button != null && bx == eles.button.x && by == eles.button.y){
                      eles.button = null;
                      eles.line = null;
                      eles.ball.setV(0,0);
                    }else if(bx > this.getAttribute("maxTouchX")/2){
                    //   var but = {"type":"circle","r":10,"x":eles.ball.x,"y":eles.ball.y,"color":"#ff09",v:{vx:ex-bx,vy:ey-by,zoom:100}}
                    //   let bullet = new Bullet(eles.ball.x,eles.ball.y,ex-bx,ey-by,10,Date.now()/1000)
                    //   eles.bullets.push(bullet);
                    }
                    
                    ongoingTouches.splice(idx, 1);
                  }  else  {
                   alert( "can't figure out which touch to end" );
                 }
               }
        },  false );
    }

    addpcListener(){
        let that=this;
        document.addEventListener("keydown",function (e){
            let player=that.world.eles.ball;
            let vx = player.v.vx > 0 ? 1: player.v.vx < 0 ? -1 : 0;
            let vy = player.v.vy > 0 ? 1: player.v.vy < 0 ? -1 : 0;
            if(e.key === "d"){
                vx=vx+1;
            }else if(e.key === "a"){
                vx=vx-1;
            }else if(e.key === "w"){
                vy=vy-1;
            }else if(e.key === "s"){
                vy=vy+1;
            }
            player.setV(vx,vy);
        });
        document.addEventListener("keyup",function (e){
            let player=that.world.eles.ball;
            let vx = player.v.vx > 0 ? 1: player.v.vx < 0 ? -1 : 0;
            let vy = player.v.vy > 0 ? 1: player.v.vy < 0 ? -1 : 0;
            if(e.key === "d"){
                vx=vx-1;
            }else if(e.key === "a"){
                vx=vx+1;
            }else if(e.key === "w"){
                vy=vy+1;
            }else if(e.key === "s"){
                vy=vy-1;
            }
            player.setV(vx,vy);
        });



    }

    copyTouch(touch) {
        return  { identifier: touch.identifier, pageX: touch.pageX, pageY: touch.pageY };
    }

    ongoingTouchIndexById(idToFind) {
        // this.world.log("by id");
        for  ( let  i=0; i < this.world.ongoingTouches.length; i++) {
          let  id = this.world.ongoingTouches[i].identifier;
          if  (id == idToFind) {
            return  i;
          }
        }
        return  -1;     // not found
    }

}



class Drawer{
    world;
    canvas;
    ctx;
    interval=25;
    constructor(world){
        let that = this;
        this.world = world;
        this.canvas = world.canvas;
        this.ctx = this.canvas.getContext( "2d" );
        setInterval(function(){that.updateCanvas();},that.interval);
    }


    updateCanvas(){
        let eles = this.world.eles;
        let ctx = this.ctx;
        ctx.fillStyle = "#fff";
        ctx.fillRect(0, 0, this.canvas.getAttribute("width"), this.canvas.getAttribute("height"));
        let mapEles = eles.mapEles;
        if(mapEles != null){
            for  ( let  i=0; i < mapEles.length; i++) {
                this.drawEle(mapEles[i],ctx);
            }
        }
        for  ( let  i=0; i < eles.permanent.length; i++) {
            let name = eles.permanent[i];
            if  (eles[name] != null) {
                // this.world.log(eles[name]);
                this.drawEle(eles[name],ctx,true)
            }
          }
        let bullets = eles.bullets;
        for  ( let  i=0; i < bullets.length; i++) {
            this.drawEle(bullets[i],ctx);

        }
        let npcs = eles.npcs;
        for  ( let  i=0; i < npcs.length; i++) {
            this.drawEle(npcs[i],ctx);
        }
    }

    drawEle(e,ctx,isPermanent){
        let cameraX = this.world.cameraX;
        let cameraY = this.world.cameraY;
        let cameraWidth = this.world.cameraWidth;
        let cameraHeight = this.world.cameraHeight;
        if(e.role === "button"){
            cameraX=0;
            cameraY=0;
        }
        // this.world.log(e.role);
        if(e.x < cameraX-100 || e.x > cameraX+cameraWidth+100 || e.y < cameraY-100 || e.y > cameraY+cameraHeight+100){
            return;
        }
       
        if(e.shape === "circle"){
            let x = e.x - cameraX;
            let y = e.y - cameraY;
            ctx.beginPath();
            ctx.arc(x, y, e.r, 0,2*Math.PI,  false );   // a circle at the start
            ctx.fillStyle = e.color;
            ctx.fill();
        }else if(e.shape === "line"){
            // this.world.log(key + ':' + JSON.stringify(e));
            let bx = e.bx - cameraX;
            let by = e.by - cameraY;
            let ex = e.ex - cameraX;
            let ey = e.ey - cameraY;
            ctx.beginPath();
            ctx.moveTo(bx,by);
            ctx.lineTo(ex,ey);
            ctx.lineWidth = 2;
            ctx.strokeStyle = e.color;
            ctx.stroke();
        }
    }


}



class Runner{
    world;
    eles;
    canvas;
    interval=5;
    constructor(world){
        let that = this;
        this.world = world;
        this.eles = world.eles;
        this.canvas = world.canvas;
        setInterval(function(){that.run()},that.interval)
    }



    run(){
        this.updatePosition();
        this.checkCrash();
    }

    checkCrash(){
        let bullets = this.eles.bullets;
        for  ( let  i=0; i < bullets.length; i++) {
            let e = bullets[i];
            if(e.x <= 0 || e.x >= this.world.mapWidth || e.y <= 0 || e.y >= this.world.mapHieght){
                bullets.splice(i,1);
                i--;
                continue;
            }
            let now = Date.now()/1000;
            if(now - e.birthTime > 8){
                bullets.splice(i,1);
                i--;
                continue;
            }
        }
        let npcs = this.eles.npcs;
        for  ( let  i=0; i < npcs.length; i++) {
            let n = npcs[i];
            let hit = false;
            for  ( let  j=0; j < bullets.length; j++) {
                let b = bullets[j];
                if(Math.pow((b.x-n.x),2) + Math.pow((b.y-n.y),2) < Math.pow((b.r+n.r),2)){
                    bullets.splice(j,1);
                    hit = true;
                    break;
                }
            }
            if(hit){
                npcs.splice(i,1);
                i--;
                continue;
            }
            n.think();
        }

       if( Math.random()*1000/this.interval<1){
           let x=Math.random()*this.world.mapWidth;
           let y=Math.random()*this.world.mapHieght;
           let ox=(Math.random()-0.5)*200;
           let oy=(Math.random()-0.5)*200;
           let npc = new Npc(x,y,ox,oy,2);
           npc.setWorld(this.world);
           npcs.push(npc);
       }

       for( let i in this.world.ongoingTouches){
            let touch = this.world.ongoingTouches[i];
            if(touch.pageX > this.canvas.getAttribute("width")/2 && touch.nowX != null){
                let p = this.eles.ball;
                // p.aim(touch.nowX-touch.pageX,touch.nowY-touch.pageY);
                p.shoot(touch.nowX-touch.pageX,touch.nowY-touch.pageY);
            }
       }

    }

    updatePosition(){
        // this.world.log("aaa");
        let eles = this.eles;
        for  ( let  i=0; i < eles.permanent.length; i++) {
            let name = eles.permanent[i];
            if  (eles[name] != null) {
                // this.world.log(eles[name]);
                this.moveEle(eles[name]);
            }
        }
        let bullets = eles.bullets;
        // this.world.log(bullets.length);
        for  ( let  i=0; i < bullets.length; i++) {
            this.moveEle(bullets[i]);
        }
        let npcs = eles.npcs;
        // this.world.log(bullets.length);
        for  ( let  i=0; i < npcs.length; i++) {
            // debugger
            this.moveEle(npcs[i]);
        }
    }

    moveEle(e){
        if(e.v != null){
            let dx = e.v.vx * e.v.vzoom * this.interval / 1000;
            let dy = e.v.vy * e.v.vzoom * this.interval / 1000;
            if((dx <= 0 && e.x > 0) || (dx > 0 && e.x < this.world.mapWidth)){
              e.x = e.x + dx; 
            }
            if((dy <= 0 && e.y > 0) || (dy > 0 && e.y < this.world.mapHieght)){
              e.y = e.y + dy;
            }
            if(e.role === "player"){
                let cameraX = this.world.cameraX;
                let cameraY = this.world.cameraY;
                let cameraWidth = this.world.cameraWidth;
                let cameraHeight = this.world.cameraHeight;
                if(e.x - cameraX < cameraWidth/3){
                    this.world.cameraX = e.x-cameraWidth/3;
                    // debugger
                }else if(e.x - cameraX > cameraWidth/3*2){
                    this.world.cameraX = e.x-cameraWidth/3*2;
                }
                if(e.y - cameraY < cameraHeight/3){
                    this.world.cameraY = e.y-cameraHeight/3;
                }else if(e.y - cameraY > cameraHeight/3*2){
                    this.world.cameraY = e.y - cameraHeight/3*2;
                }
            }
        }else{}
    }
}



class WorldIniter{
    world;
    constructor(world){
        this.world = world;
        this.init();
    }
    init(){
        this.initMap();
    }
    initMap(){
        this.world.eles.mapEles= new  Array(); 
        let mapEles = this.world.eles.mapEles;
        for(let i = 0 ;i<this.world.mapWidth;i= i+ 150){
            for(let j = 0 ;j< this.world.mapHieght; j = j+150){
                mapEles.push(new MapCircleEle(i,j,5,"#0f0"));
            }
        }
    }
}


class Bullet{
    x=0;
    y=0;
    v={"vx":0,"vy":0,"vzoom":1};
    // vx=0;
    // vy=0;
    // vzoom=1;
    shape = "circle";
    r = 10;
    color = "#f007";
    role = "bullet";
    birthTime = 0;
    constructor(x,y,vx,vy,vzoom,time=Date.now()/1000){
        this.x = x;
        this.y = y;
        this.v.vx = vx;
        this.v.vy = vy;
        this.v.vzoom = vzoom;
        this.birthTime = time;
    }
}


class BasicEle{
    x=0;
    y=0;
    color = "#7777";
    role = "basic";
    birthTime = Date.now();
    shape = "non";
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
}

class MobileEle extends BasicEle{
    v={"vx":0,"vy":0,"vzoom":1};
    ox = 0;
    oy = 0;
    constructor(x,y,ox,oy,vzoom){
        super(x,y);
        this.v.vzoom = vzoom;
        this.setV(ox,oy);
    }

    setV(ox,oy,zoom){
        // debugger
        if(zoom != null){
            this.v.vzoom = zoom;
        }
        this.ox = ox;
        this.oy = oy;
        // let xy=Math.pow(Math.pow(this.ox,2)+Math.pow(this.oy,2) , 0.5);
        // let vx = this.ox/xy*100;
        // let vy = this.oy/xy*100;
        let v = this.normalizingVector(this.ox,this.oy);
        // debugger
        this.v.vx=v.x*this.v.vzoom*100;
        this.v.vy=v.y*this.v.vzoom*100;
        if(isNaN(this.v.vx)){
            debugger
        }
    }

    normalizingVector(x,y){
        // let xy= Math.pow( x == 0 ? 0 : Math.pow(this.ox,2)  + y == 0 ? 0 : Math.pow(this.oy,2) , 0.5);
        // let vx = xy == 0 ? 0 : x/xy;
        // let vy = xy == 0 ? 0 : y/xy;
        let xy= Math.pow(  Math.pow(this.ox,2)  +Math.pow(this.oy,2) , 0.5);
        let vx = x/xy;
        let vy = y/xy;
        if(x==0 && y==0){
            vx = 0;
            vy = 0;
        }
        return {"x":vx,"y":vy};
    }
}

class Npc extends MobileEle{
    shape="circle";
    r=30;
    color="#000a";
    world;
    constructor(x,y,vx,vy,vzoom){
        super(x,y,vx,vy,vzoom);
        this.role="npc";
    }

    setWorld(world){
        this.world = world;
    }
    think(){
        if(this.world == null){
            return
        }
        let player = this.world.eles.ball;
        if(player == null){
            return;
        } 
        let dx = (player.x - this.x - this.v.vx)/50
        let dy = (player.y - this.y - this.v.vy)/50
        this.ox = this.v.vx + dx;
        this.oy = this.v.vy + dy;
        // debugger
        this.setV(this.ox,this.oy);
    }
}


class Player extends MobileEle{
    shape="circle";
    r=30;
    color="#000a";
    useingGun;
    world;
    constructor(x,y,vx,vy,vzoom,color){
        super(x,y,vx,vy,vzoom);
        this.color=color;
        this.role="player";
    }

    setGun(gun){
        this.useingGun = gun;
    }
    setWorld(world){
        this.world=world;
    }

    shoot(ox,oy){
        this.useingGun.x=this.x;
        this.useingGun.y=this.y;
        let b = this.useingGun.shoot(ox,oy);
        if(null != b && null != this.world){
            this.world.eles.bullets.push(b);
        }
    }
    
    aim(ox,oy){
        this.useingGun.setOrientation(ox,oy);
    }
}


class Weapon{
    cd=100;
    lastUsedTime=0;
    type="basic";
    constructor(cd){
        this.cd = cd;
    }
}


class Gun extends Weapon{
    bulletSpeed=90;
    orientationX=1;
    orientationY=1;
    x;
    y;
    constructor(cd,x,y,ox,oy){
        super(cd);
        this.x =x;
        this.y = y;
        this.orientationX= ox;
        this.orientationY = oy;
    }
    setOrientation(ox,oy){
        this.orientationX = ox;
        this.orientationY = oy;
    }

    shoot(ox,oy){
        this.orientationX = ox;
        this.orientationY = oy;
        if(Date.now()-this.lastUsedTime > this.cd){
            let xy=Math.pow(Math.pow(this.orientationX,2)+Math.pow(this.orientationY,2) , 0.5);
            let vx = this.orientationX/xy*100;
            let vy = this.orientationY/xy*100;
            this.lastUsedTime = Date.now();
            return new Bullet(this.x,this.y,vx,vy,this.bulletSpeed);
        }else{
            return null;
        }
    }
}


class SubmachineGun extends Gun{
    constructor(){
        super(10,1,1,1,1)
        // this.cd = 0;
        this.bulletSpeed = 20;
    }

}


// class CircleButton extends BasicEle{
//     {"r":50,"x":touches[i].pageX,"y":touches[i].pageY,"color":"#0002"}
//     constructor(x,y,r,color){
//         super(x,y);
//         this.shape="circle";
//         this.role = "Circlebutton"
//     }
// }


class MapLineEle extends BasicEle{
    bx = 0;
    by = 0;
    ex = 0;
    ey = 0;
    constructor(bx,by,ex,ey,color){
        super(bx,by);
        this.shape = "line";
        this.role = "mapele";
        this.color = color;
    }
}


class MapCircleEle extends BasicEle{
    r=0;
    constructor(x,y,r,color){
        super(x,y);
        this.shape = "circle";
        this.role = "mapele";
        this.color = color;
        this.r=r;
    }
}

